package com.cp.admin.core.util;

import com.alibaba.fastjson.JSON;
import com.cp.admin.api.utils.StrUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 签名工具
 * @author 解风
 * @version 2018-01-09
 */

public class SignUtils {
    private static final int INT1000 = 1000;
    private static final String SIGNATURE = "signature";
    private static final int SECOND300 = 300;
    private static Logger logger = LoggerFactory.getLogger(SignUtils.class);
    private static final String CONTENTENCODING = "UTF-8";

    /**
     * 验证接口参数签名
     * 所有参数都放入request的param中，不放入header里面，也不从header里面取参数
     * 参数signature不参在后台不参与签名，且参数长度大于1000的参数也不参与签名
     * public_key的字符串固定，参与签名计算
     * 同时还要校验时间是否超时
     * @param request HttpServletRequest
     * @return boolean
     */
    public static boolean valiSignature(HttpServletRequest request) {
        //1、获取请求参数
        Map<String, String> paramMap = getParams(request);
        String paramsStr = getOrderParamString(paramMap);//排序后的参数串
        String signature = request.getParameter(SIGNATURE);// 签名信息
        String public_key = "2F8341CBD52B1EEDB49B293CB01C0DDB";// public_key为“重庆纵情向前科技”的md5值
        //验证必填参数
        // 下面的参数都建议放到request中，便于各个平台接入
        if(StrUtils.isEmpty(signature)){//签名为空
            return false;
        }
        //2、后端签名
        logger.info("---paramsStr------->"+paramsStr);
        logger.info("---MD5-1------->"+ Md5Utils.encryption(paramsStr));
        String msg = public_key + Md5Utils.encryption(paramsStr).toUpperCase();
        logger.info("---msg------->"+msg);
        String local_signature = Md5Utils.encryption(msg);
        logger.info("---local_signature------->"+local_signature);
        //3、校验签名是否一致
        long ts = Long.parseLong(paramMap.get("timestamp"));
        boolean success = signature.equalsIgnoreCase(local_signature) && checkTimeOut(ts, SECOND300);
        if(!success){
            logger.info("签名错误:"+signature+";=="+local_signature+"接口参数paramsStr:"+paramsStr+";==接口参数paramMap:"+ JSON.toJSONString(paramMap));
        }
        return success;
    }

    private static Map<String,String> getParams(HttpServletRequest request){
        Map<String, String> urlParams = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        if(requestParams !=null){
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                // 数据中心把signature字段放到request请求中，该字段不参与签名
                if(SIGNATURE.equalsIgnoreCase(name)) {
                    continue;
                }
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";

                int len = values.length;
                for (int i = 0; i < len; i++) {
                    // 当参数的值大于1000,不参与签名
                    if(values[i].length() > INT1000) {
                        continue;
                    }
                    valueStr = (i == len - 1) ? valueStr + values[i]  : valueStr + values[i] + ",";
                }
                try {
//                    valueStr = URLDecoder.decode(valueStr, CONTENTENCODING);
                    valueStr = URLEncoder.encode(valueStr, CONTENTENCODING);
//                    System.out.println("------------------->"+name + "======="+ valueStr);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                urlParams.put(name, valueStr);
            }
        }
        return urlParams;
    }

    private static String getOrderParamString(Map<String, String> parms){
        StringBuffer sb = new StringBuffer();
        try {
            ArrayList<String> aa = new ArrayList<String>(parms.keySet());
            Collections.sort(aa);
            for (String key : aa) {
//                sb.append(key).append("=").append(java.net.URLEncoder.encode(parms.get(key),"UTF-8")).append("&");
                sb.append(key).append("=").append(parms.get(key)).append("&");
            }
            if (sb.length() > 1) {
                sb.deleteCharAt(sb.length()-1);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * client传递过来的时间，在正负5分钟内都有效
     * @param ts client传递过来的时间
     * @param second 秒
     * @return boolean
     */
    private static boolean checkTimeOut(long ts,int second) {
        Date date = new Date();
        long min = date.getTime() / 1000 - second;
        long max = date.getTime() / 1000 + second;
        return ts < min || ts > max;
    }
}
